from decimal import Decimal
from django.utils import timezone

from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import serializers
from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
import logging

logger = logging.getLogger('django')


class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class SaveOrderSerializer(serializers.ModelSerializer):
    """
    下单数据序列化器
    """

    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        """
        保存订单
        :param validated_data:
        :return:
        """

        address = validated_data['address']
        pay_method = validated_data['pay_method']

        # 获取当前下单用户
        user = self.context['request'].user

        # 查询购物车redis sku_id count selected
        redis_conn = get_redis_connection('cart')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        if not cart:
            raise serializers.ValidationError('没有需要结算的商品')

        # 创建事务, 开启事务
        with transaction.atomic():
            # 创建一个保存点
            save_id = transaction.savepoint()
            # 保存订单
            # 生成订单编号order_id
            # 20180702150101  9位用户id
            # datetime -> str   strftime
            #  str -> datetime  strptime
            order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        try:
            # 保存订单
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=0,
                total_amount=Decimal(0),
                freight=Decimal(10.00),
                pay_method=pay_method,
                status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else
                OrderInfo.ORDER_STATUS_ENUM['UNPAID']

            )

            # 创建订单基本信息表记录 OrderInfo
            # 查询商品数据库, 获取商品数据
            sku_id_list = cart.keys()
            # 遍历需要结算的商品数据
            for sku_id in sku_id_list:
                while True:
                    sku = SKU.objects.get(id=sku_id)
                    original_stock = sku.stock
                    original_sales = sku.sales
                    sku_count = cart[sku.id]
                    # 判断库存
                    if sku_count > original_stock:
                        # 回滚到保存点
                        transaction.savepoint_rollback(save_id)
                        raise serializers.ValidationError('商品%s库存不足' % sku.name)
                    # 库存减少, 销量增加
                    new_stock = original_stock - sku_count
                    new_sales = original_sales + sku_count
                    result = SKU.objects.filter(id=sku_id, stock=original_stock, sales=original_sales).update(
                        stock=new_stock,
                        sales=new_sales)
                    if result == 0:
                        continue

                    order.total_count += sku_count
                    order.total_amount += (sku.price * sku_count)
                    # 创建订单商品信息表记录 OrderGoods
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    break

            order.save()

        except serializers.ValidationError:
            raise

        except Exception as e:
            logger.error(e)
            transaction.savepoint_rollback(save_id)
            raise
        else:
            transaction.savepoint_commit(save_id)

        pl = redis_conn.pipeline()
        # 删除购物车中已经结算的商品
        pl.hdel('cart_%s' % user.id, *cart_selected)

        pl.srem('cart_selected_%s' % user.id, *cart_selected)

        pl.execute()
        # 返回OrderInfo对象

        return order
